package cn.tedu.v2_1;
import java.io.*;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

/**启动服务器·----N多客户端链接服务器----accept【返回一个客户端Socket】
 *    缺点：只知道来人ip，并不知道哪个IP服务器端说话
 *
 *    调整：获取IP地址的方法，移动--CS多线程中处理！
 *
 *    思路：1.删除 N 多客户端连接服务器--打印IP的消息【证明连接上】
 *         2.获取IP信息--存入线程CS类中：
 *         处理多个客户端链接可否返回【客户端：】
 *         CS构造器--->start方法---创建线程对象---传入客户端socket
 *                                             并且赋值当前线程Socket对象
 *         【保证一个客户端连接服务器端，正确返回，等同于找到正确客户端】
 *         ①私有化，目的：保证IP信息准确，供当前CS类所用
 *         ②构造器：完成ip的获取方法：创建CS线程，明确客户端Socket
 *                                           立即给客户端进行IP赋值
 *                 socket.getInetAddress() 获取当前主机IP信息对象
 *                 socket.getInetAddress().getHostAddress() 获取主机IP字符串
 *
 *         服务器显示 客户端内容 打印效果如下
 *            172.20.10.3的客户端说:
 *            --------------------------
 *            优化操作：针对【ServerSocket类与Socket 程序健壮性】
 *            ServerSocket  运行在服务器socket通讯类-----关闭问题
 *            关闭方法:服务器端main、start方法中finally关闭
 *            为什么在以上两个位置关闭，服务器通讯类:
 *            因为关闭后将无法再接收任何新的客户端的链接【所有功能提供完毕】
 *            serverSocket!=null
 *            关闭通讯类--判断是否为对象null
 *            isClosed()判断ServerSocket(Socket)对象是否关闭
 *                      默认情况:true，false表示没有关闭
 *            CS多线程类：处理各个客户端
 *            Cs线程中 Socket 通讯类 【同IO流操作同在】        -----关闭问题
 *            判断逻辑：socket!=null 对象是否被赋值
 *                    !socket.isClosed 对象没有被关闭
 *
 */
public class Server {
    private ServerSocket serverSocket;
    public Server(){
        try {
            serverSocket=new ServerSocket(1019);
        } catch (BindException e){
            System.out.println("请检查端口号，被占用~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        Socket socket=null;

        String ip=null;
        try {
            while(true) {
                System.out.println("等待客户端连接");
                socket = serverSocket.accept();

                CS cs = new CS(socket);
                Thread t1 = new Thread(cs);
                t1.start();
            }
        } catch (IOException e) {
            System.out.println(ip+"客户端链接断开链接~");
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                System.out.println("客户端socket断开链接~");
            }finally {
                //1.正确关闭ServerSocket--->start 方法中
                //不为空：是否初始化  尚未关闭：检查对象是否关闭
                if (serverSocket!=null&&serverSocket.isClosed()){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        System.out.println("服务器关闭失败~~");
                    }
                    System.out.println("服务器关闭成功~~Over");
                }
            }
        }
    }
    public static void main(String[] args){
       Server server=new Server();
        server.start();
    }

    private class CS implements Runnable {

        private Socket socket;


        private String ip;


        public CS(Socket s){
            this.socket=s;
            //3.CS线程对象：IP赋值
        ip=socket.getInetAddress().getHostAddress();

        }


        public void run() {
            BufferedReader br = null;
            try {
                br = new BufferedReader( new InputStreamReader(socket.getInputStream(),"UTF8"));

                while (true) {
                    String str = br.readLine();
                    System.out.println(ip+"客户端说：" + str);
                }
            } catch (UnsupportedEncodingException e) {
                System.out.println("请检查客户端/服务器端编码集：不一致~");
            } catch (SocketException e) {
                System.out.println("客户端链接被重置了~");
            } catch (IOException e) {
                System.out.println("客户端链接失效了~");
            } finally {//一定关闭：先关闭流、后关Socket
                //关闭流  关闭socket
                if (br != null)
                    try {
                        br.close();
                    } catch (IOException e) {
                        System.out.println("读入流断开链接~");
                    }
                //2.关闭CS多线程类中---运行的Socket通讯录
                if (socket!=null&&!socket.isClosed()){
                    System.out.println(ip+"一个客户端退出服务器链接~~");
                    try {
                        socket.close();
                    } catch (IOException e) {
                        System.out.println(ip+"一个客户端退出链接异常~~");
                    }

                }
            }//客户端---socket正确关闭---拓展：客户端+获取IP
        }
    }
}
